#include "lib.h"

// 精确延迟，单位：0.1ms
// period：延迟周期数 <= 65535
void delay(unsigned int period)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_TimeBaseInitTypeDef ti; //初始化定时器结构体体变量
    ti.TIM_Prescaler = 7199; //分频系数
    ti.TIM_CounterMode = TIM_CounterMode_Up; //计数方式
    ti.TIM_Period = period - 1; //周期
    TIM_TimeBaseInit(TIM2, &ti); //初始化定时器
    TIM_SetCounter(TIM2, 0); //清0
    TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除更新标志位
    TIM_Cmd(TIM2, ENABLE); //启动定时器2
    while (TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) == RESET)
        ;
    TIM_Cmd(TIM2, DISABLE); //关闭定时器2
}

// 定时器初始化
void TIM2_Init(unsigned int period)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_TimeBaseInitTypeDef ti; //初始化定时器结构体体变量
    ti.TIM_Prescaler = 7199; //分频系数
    ti.TIM_CounterMode = TIM_CounterMode_Up; //计数方式
    ti.TIM_Period = period - 1; // 最大周期
    TIM_TimeBaseInit(TIM2, &ti); //初始化定时器
    TIM_SetCounter(TIM2, 0); //计数器清0
    TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除更新标志位
}

// 开始计时并检测按键是否弹起，弹起则返回1，计时器结束返回0；
// ms: 计时时间，单位毫秒，最大为6553.5ms
// 不推荐用于循环计时，此函数每次开启计时器都会进行初始化，因为初始化开销较大，用于循环计时会导致误差增大
char TimedCheckKeyUp(unsigned int ms)
{
    TIM2_Init(ms * 10);
    TIM_Cmd(TIM2, ENABLE); //启动定时器2
    while (TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) == RESET) {
        if (GetKey() == KEY_NONE) {
            TIM_Cmd(TIM2, DISABLE); //关闭定时器2
            return 1;
        }
    }
    TIM_Cmd(TIM2, DISABLE); //关闭定时器2
    return 0;
}

// 键代码转ASCII字符
// KeyCode：键代码
// 返回：对应ASCII字符,如果找不到则返回CH_NONE
unsigned char KeyToChar(unsigned char KeyCode)
{
    switch (KeyCode) {
    case KEY_0:
        return '0';
    case KEY_1:
        return '1';
    case KEY_2:
        return '2';
    case KEY_3:
        return '3';
    case KEY_4:
        return '4';
    case KEY_5:
        return '5';
    case KEY_6:
        return '6';
    case KEY_7:
        return '7';
    case KEY_8:
        return '8';
    case KEY_9:
        return '9';
    case KEY_ENTER:
        return '\n';
    case KEY_BACKSPACE:
        return CH_BACKSPACE;
    case KEY_ESC:
        return CH_ESC;
    case KEY_ADD:
        return CH_ADD;
    case KEY_DEL:
        return CH_DEL;
    default:
        return CH_NONE;
    }
}



// 阻塞当前进程以获取一个字符
// 返回对应字符,未定义按键返回CH_NONE
char getch()
{
    unsigned char key = KEY_NONE;
    while (key == KEY_NONE) {
        key = GetKey();
    }
    while (GetKey() != KEY_NONE) { }
    return KeyToChar(key);
}



// 从键盘输入并显示字符到屏幕，输入回车或达到限制长度时结束输入
// x；显示横坐标
// y：显示纵坐标
// str：字符串缓冲区
// 返回：输入回车结束返回0，溢出返回1，ESC返回2
char ShowAndGets(unsigned char x, unsigned char y, char* str)
{
    unsigned char i = 0;
    unsigned char key = KEY_NONE;
    unsigned char ch = CH_NONE;
    char flag = 0;
    char stopflag = 0;
    char strbuff[BUFFSIZE] = "";

    // for (i = 0; (ch != '\n') && (i < length); i++) {
    while (1) {
        key = KEY_NONE;
        flag = 0;

        // 等待按键按下
        while (key == KEY_NONE) {
            key = GetKey();
        }

        // 按键被按下
        ch = KeyToChar(key);

        // 无效退格
        if (ch == CH_BACKSPACE && i == 0) {
            continue;
        }

        // 屏蔽其它按键
        if (ch == CH_NONE || ch == CH_ADD || ch == CH_DEL) {
            continue;
        }

        // 判断是否达到缓冲区
        if (i >= BUFFSIZE - 1) {
            strcpy(str, strbuff);
            return 1;
        }

        if (ch == CH_BACKSPACE) {
            i--;
            strbuff[i] = 0;
            OLED_ShowChar(i * 8 + x, y, 32);
        } else if (ch == '\n') {
            strcpy(str, strbuff);
            return 0;
        } else if (ch == CH_ESC) {
            return 2;
        } else {
            strbuff[i] = ch;
            OLED_ShowChar(i * 8 + x, y, ch);
            i++;
        }

        // 等待按键松开（长按）
        while (GetKey() != KEY_NONE) {
            if (flag == 0) {
                stopflag = TimedCheckKeyUp(500);
                if (stopflag == 1) {
                    break;
                }
                flag = 1;
            } else {
                stopflag = TimedCheckKeyUp(100);
                if (stopflag == 1) {
                    flag = 0;
                    break;
                }
            }

            // 无效退格
            if (ch == CH_BACKSPACE && i == 0) {
                continue;
            }

            // 屏蔽其它按键
            if (ch == CH_NONE || ch == CH_ADD || ch == CH_DEL) {
                continue;
            }

            // 判断是否达到缓冲区
            if (i >= BUFFSIZE - 1) {
                strcpy(str, strbuff);
                return 1;
            }

            if (ch == CH_BACKSPACE) {
                i--;
                strbuff[i] = 0;
                OLED_ShowChar(i * 8 + x, y, 32);
            } else if (ch == '\n') {
                strcpy(str, strbuff);
                return 0;
            } else {
                strbuff[i] = ch;
                OLED_ShowChar(i * 8 + x, y, ch);
                i++;
            }
        }
    }
}